package com.beiji.usercentert.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.beiji.usercentert.commoon.ErrorCode;
import com.beiji.usercentert.constant.UserConstant;
import com.beiji.usercentert.exception.BusinessException;
import com.beiji.usercentert.mapper.UserMapper;
import com.beiji.usercentert.model.domain.User;
import com.beiji.usercentert.service.UserService;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.beiji.usercentert.constant.UserConstant.USER_LOGIN_STATE;

/**
 * @author wangzhi
 * @description 针对表【user(用户表)】的数据库操作Service实现
 * @createDate 2024-06-23 17:17:47
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    //加盐
    private static final String SALT = "beiji";

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {

        //校验
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword, planetCode)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        //不包含特殊字符
        String vaildPattern = "^[a-zA-Z0-9_]{4,}$";
        Matcher matcher = Pattern.compile(vaildPattern).matcher(userAccount);
        boolean matches = matcher.matches();
        if (!matches) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "有特殊字符");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户长度");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码");
        }
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次密码不一致");
        }
        //查看星球编号是否合法
        if (planetCode.length() > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编号不合法");
        }
        //检验用户是否存在
        User user = this.lambdaQuery()
                .eq(User::getUserAccount, userAccount)
                .one();
        if (ObjectUtils.isNotEmpty(user)) {
            throw new BusinessException(ErrorCode.NULL_DATA, "数据重复");
        }

        //星球编号是否重复
        User user1 = this.lambdaQuery()
                .eq(User::getPlanetCode, planetCode)
                .one();
        if (ObjectUtils.isNotEmpty(user1)) {
            throw new BusinessException(ErrorCode.NULL_DATA, "数据重复");
        }

        //密码加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());

        //插入用户数据
        User addUser = new User();
        addUser.setUserAccount(userAccount);
        addUser.setUserPassword(encryptPassword);
        addUser.setPlanetCode(planetCode);
        boolean result = this.save(addUser);
        if (!result) {
            return -1;
        }
        return addUser.getId();
    }

    /**
     * 修改用户信息
     *
     * @param user      用户
     * @param loginUser
     * @return 1 2
     */
    @Override
    public Integer UpdateUser(User user, User loginUser) {
        Long userId = user.getId();
        if (userId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //todo 判断除了id之外其他的元素是否全为null
        //管理员可以修改用户信息
        //当前用户可以修改用户信息
        if (!isAdmin(loginUser) && !userId.equals(loginUser.getId())) {
            return null;
        }

        //查询修改的用户是否存在
        User oldUser = userMapper.selectById(userId);
        //非空判断
        if (ObjectUtils.isEmpty(oldUser)) {
            throw new BusinessException(ErrorCode.NULL_DATA);
        }

        //修改用户
        int result = userMapper.updateById(user);
        return result;

    }

    /**
     * 用户登录
     * @param userAccount  用户账号
     * @param userPassword 用户密码
     * @param request
     * @return
     */
    @Override
    public User doLogin(String userAccount, String userPassword, HttpServletRequest request) {
        //校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //不包含特殊字符
        String vaildPattern = "^[a-zA-Z0-9_]{4,}$";
        Matcher matcher = Pattern.compile(vaildPattern).matcher(userAccount);
        boolean matches = matcher.matches();
        if (!matches) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //md5加密
        String safetyPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        //根据账号和密码查询用户是否存在
        User user = this.lambdaQuery()
                .eq(User::getUserAccount, userAccount)
                .eq(User::getUserPassword, safetyPassword)
                .one();

        if (ObjectUtils.isEmpty(user)) {
            log.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        User safetyUser = getSafetyUser(user);

        //记录用户登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);

        //返回脱敏后的用户信息
        return safetyUser;
    }

    //脱敏
    public User getSafetyUser(User originUser) {
        //脱敏
        User safetyUser = new User();
        safetyUser.setId(originUser.getId());
        safetyUser.setUsername(originUser.getUsername());
        safetyUser.setUserAccount(originUser.getUserAccount());
        safetyUser.setAvatarUrl(originUser.getAvatarUrl());
        safetyUser.setGender(originUser.getGender());
        safetyUser.setPhone(originUser.getPhone());
        safetyUser.setEmail(originUser.getEmail());
        safetyUser.setPlanetCode(originUser.getPlanetCode());
        safetyUser.setUserRole(originUser.getUserRole());
        safetyUser.setUserStatus(originUser.getUserStatus());
        safetyUser.setCreateTime(originUser.getCreateTime());
        safetyUser.setTags(originUser.getTags());
        return safetyUser;
    }

    /**
     * 用户注销
     *
     * @param request
     * @return
     */
    @Override
    public Integer userLogout(HttpServletRequest request) {
        //移除session
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return 1;
    }

    /**
     * 根据标签搜索用户，多个标签都存在
     *
     * @param tagList 标签
     * @return 用户
     */
    public List<User> searchUserByTag(List<String> tagList) {
        /*//非空判断
        if (CollectionUtils.isEmpty(tagList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //创建条件构造器
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        for (String tag : tagList) {
            queryWrapper = queryWrapper.like(User::getTags, tag);
        }

        //查询用户
        List<User> userList = userMapper.selectList(queryWrapper);

        return userList.stream().map(this::getSafetyUser).collect(Collectors.toList());*/


        //内存查询
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        List<User> userList = userMapper.selectList(queryWrapper);

        //如果数据多的话可以开启多线程
        //stream.parallelStream
        return userList.stream().filter(user -> {
            String tags = user.getTags();
            if (StringUtils.isEmpty(tags)) {
                return false;
            }
            Gson gson = new Gson();
            Set<String> tagSet = gson.fromJson(tags, new TypeToken<Set<String>>() {
            }.getType());
            for (String tag : tagList) {
               return tagSet.contains(tag);
            }
           return false;
        }).map(this::getSafetyUser).collect(Collectors.toList());
    }

    /**
     * 获取推荐用户
     * @return
     */
    public Page<User> recommendUsers(Long userId, Integer pageNum, Integer pageSize){
        String redisKey = String.format("yupo:user:recommend:%s", userId);
        //读缓存
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        Page<User> userPage = (Page<User>) opsForValue.get(redisKey);
        if (ObjectUtils.isNotEmpty(userPage)) {
            return userPage;
        }

        //缓存没有，查数据库，再存入缓存，最后返回
        //存缓存的时候设置过期时间
        //LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        userPage= this.page(new Page<>(pageNum, pageSize));
        opsForValue.set(redisKey, userPage, 30000, TimeUnit.MILLISECONDS);
        return userPage;
    }

    @Override
    public boolean isAdmin(User currentUser) {
        if (currentUser.getUserRole() != UserConstant.ADMIN_ROLE) {
            return false;
        }
        return true;
    }

    /**
     * 获得当前用户
     * @param request 请求
     * @return 用户
     */
    @Override
    public User getLoginUser(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User user = (User) userObj;
        //非空判断
        if (user == null) {
            throw new BusinessException(ErrorCode.NULL_DATA);
        }

        return user;
    }
}